using System.Collections.Generic;
using OracleInternal.ServiceObjects;

namespace OracleInternal.Common
{
	internal class StatementCache
	{
		private object m_sync = new object();

		private ulong m_lastUsedCount;

		private Dictionary<string, CachedStatement> m_cache;

		internal int m_maxCacheSize;

		internal int Count
		{
			get
			{
				if (m_cache != null)
				{
					return m_cache.Count;
				}
				return 0;
			}
		}

		internal List<long> Purge(int targetSize = 0)
		{
			List<long> list = new List<long>();
			CachedStatement cachedStatement = null;
			lock (m_sync)
			{
				for (int num = m_cache.Count; num > targetSize; num--)
				{
					cachedStatement = RemoveLRU();
					if (cachedStatement != null)
					{
						list.Add(cachedStatement.m_cursorId);
					}
				}
				return list;
			}
		}

		internal void ClearAllCursorIds()
		{
			lock (m_sync)
			{
				foreach (KeyValuePair<string, CachedStatement> item in m_cache)
				{
					item.Value.m_cursorId = 0;
					item.Value.m_bDefinesDone = false;
				}
			}
		}

		internal StatementCache(int maxCacheSize)
		{
			m_maxCacheSize = maxCacheSize;
			m_cache = new Dictionary<string, CachedStatement>(m_maxCacheSize);
		}

		internal CachedStatement RemoveLRU()
		{
			string text = null;
			ulong num = ulong.MaxValue;
			CachedStatement cachedStatement = null;
			foreach (KeyValuePair<string, CachedStatement> item in m_cache)
			{
				if (item.Value.m_lastUsedCount < num)
				{
					num = item.Value.m_lastUsedCount;
					text = item.Key;
				}
			}
			if (text != null)
			{
				cachedStatement = m_cache[text];
				cachedStatement.m_bIsPooled = false;
				if (!cachedStatement.m_hasExclusiveOwnershipOfCursorInfo)
				{
					cachedStatement = null;
				}
				m_cache.Remove(text);
			}
			return cachedStatement;
		}

		internal CachedStatement Put(string cmdText, CachedStatement cachedStmnt)
		{
			if (cachedStmnt.m_bIsPooled)
			{
				cachedStmnt.m_lastUsedCount = ++m_lastUsedCount;
				cachedStmnt.m_hasExclusiveOwnershipOfCursorInfo = true;
				return null;
			}
			CachedStatement value = null;
			lock (m_sync)
			{
				if (m_cache.TryGetValue(cmdText, out value))
				{
					if (value.m_hasExclusiveOwnershipOfCursorInfo)
					{
						return cachedStmnt;
					}
					cachedStmnt.m_hasExclusiveOwnershipOfCursorInfo = true;
					cachedStmnt.m_lastUsedCount = ++m_lastUsedCount;
					m_cache[cmdText] = cachedStmnt;
					return null;
				}
				if (m_cache.Count >= m_maxCacheSize)
				{
					value = RemoveLRU();
				}
				cachedStmnt.m_hasExclusiveOwnershipOfCursorInfo = true;
				cachedStmnt.m_lastUsedCount = ++m_lastUsedCount;
				cachedStmnt.m_bIsPooled = true;
				m_cache.Add(cmdText, cachedStmnt);
				return value;
			}
		}

		internal void Get(string cmdText, out CachedStatement cachedStmnt, out SQLMetaData metadata, out SQLInfo sqlInfo)
		{
			sqlInfo = null;
			metadata = null;
			cachedStmnt = null;
			lock (m_sync)
			{
				if (m_cache.TryGetValue(cmdText, out cachedStmnt))
				{
					sqlInfo = cachedStmnt.sqlInfo;
					metadata = cachedStmnt.statementdata;
					cachedStmnt.m_lastUsedCount = m_lastUsedCount++;
					if (!cachedStmnt.m_hasExclusiveOwnershipOfCursorInfo)
					{
						cachedStmnt = null;
					}
					else
					{
						cachedStmnt.m_hasExclusiveOwnershipOfCursorInfo = false;
					}
				}
			}
		}

		internal bool PeekForSQLMetaInfo(string cmdText, out SQLInfo info, out SQLMetaData data)
		{
			data = null;
			info = null;
			try
			{
				CachedStatement value = null;
				if (m_cache.TryGetValue(cmdText, out value))
				{
					data = value.statementdata;
					info = value.sqlInfo;
				}
			}
			catch
			{
				data = null;
				info = null;
			}
			if (data != null)
			{
				return info != null;
			}
			return false;
		}
	}
}
